/**
 * 表单验证工具库
 * @author Wu.Liang
 * @description 提供常用的表单验证规则和工具函数
 */

// 验证规则类型
export interface ValidateRule {
    required?: boolean
    message?: string
    trigger?: 'blur' | 'change' | string[]
    min?: number
    max?: number
    len?: number
    pattern?: RegExp
    validator?: (rule: any, value: any, callback: Function) => void
    type?: 'string' | 'number' | 'boolean' | 'method' | 'regexp' | 'integer' | 'float' | 'array' | 'object' | 'enum' | 'date' | 'url' | 'hex' | 'email'
}

// 常用正则表达式
export const REGEX = {
    // 手机号
    mobile: /^1[3-9]\d{9}$/,
    // 邮箱
    email: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
    // 身份证号
    idCard: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
    // 固定电话
    phone: /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/,
    // 网址
    url: /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/,
    // 中文
    chinese: /^[\u4e00-\u9fa5]{0,}$/,
    // 英文
    english: /^[a-zA-Z]+$/,
    // 英文数字
    englishNumber: /^[A-Za-z0-9]+$/,
    // 数字
    number: /^\d+$/,
    // 整数
    integer: /^-?\d+$/,
    // 小数
    decimal: /^-?\d+\.?\d*$/,
    // 邮政编码
    postcode: /^[1-9]\d{5}$/,
    // IP地址
    ip: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
    // MAC地址
    mac: /^([0-9a-fA-F]{2})(([/\s:-][0-9a-fA-F]{2}){5})$/,
    // 银行卡号
    bankCard: /^[1-9]\d{9,29}$/,
    // 车牌号
    carNumber: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/,
    // QQ号
    qq: /^[1-9][0-9]{4,10}$/,
    // 微信号
    wechat: /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/,
    // 密码（6-20位字母数字组合）
    password: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,20}$/,
    // 强密码（8-20位，包含大小写字母、数字、特殊字符）
    strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,20}$/
}

// 验证函数
export const validators = {
    /**
     * 必填验证
     */
    required: (message = '此项为必填项'): ValidateRule => ({
        required: true,
        message,
        trigger: 'blur'
    }),

    /**
     * 长度验证
     */
    length: (min: number, max: number, message?: string): ValidateRule => ({
        min,
        max,
        message: message || `长度应在 ${min} 到 ${max} 个字符之间`,
        trigger: 'blur'
    }),

    /**
     * 最小长度验证
     */
    minLength: (min: number, message?: string): ValidateRule => ({
        min,
        message: message || `最少输入 ${min} 个字符`,
        trigger: 'blur'
    }),

    /**
     * 最大长度验证
     */
    maxLength: (max: number, message?: string): ValidateRule => ({
        max,
        message: message || `最多输入 ${max} 个字符`,
        trigger: 'blur'
    }),

    /**
     * 手机号验证
     */
    mobile: (message = '请输入正确的手机号'): ValidateRule => ({
        pattern: REGEX.mobile,
        message,
        trigger: 'blur'
    }),

    /**
     * 邮箱验证
     */
    email: (message = '请输入正确的邮箱地址'): ValidateRule => ({
        type: 'email',
        message,
        trigger: 'blur'
    }),

    /**
     * 身份证号验证
     */
    idCard: (message = '请输入正确的身份证号'): ValidateRule => ({
        pattern: REGEX.idCard,
        message,
        trigger: 'blur'
    }),

    /**
     * 网址验证
     */
    url: (message = '请输入正确的网址'): ValidateRule => ({
        type: 'url',
        message,
        trigger: 'blur'
    }),

    /**
     * 数字验证
     */
    number: (message = '请输入数字'): ValidateRule => ({
        type: 'number',
        message,
        trigger: 'blur'
    }),

    /**
     * 整数验证
     */
    integer: (message = '请输入整数'): ValidateRule => ({
        pattern: REGEX.integer,
        message,
        trigger: 'blur'
    }),

    /**
     * 数字范围验证
     */
    numberRange: (min: number, max: number, message?: string): ValidateRule => ({
        type: 'number',
        min,
        max,
        message: message || `请输入 ${min} 到 ${max} 之间的数字`,
        trigger: 'blur'
    }),

    /**
     * 中文验证
     */
    chinese: (message = '只能输入中文'): ValidateRule => ({
        pattern: REGEX.chinese,
        message,
        trigger: 'blur'
    }),

    /**
     * 英文验证
     */
    english: (message = '只能输入英文'): ValidateRule => ({
        pattern: REGEX.english,
        message,
        trigger: 'blur'
    }),

    /**
     * 英文数字验证
     */
    englishNumber: (message = '只能输入英文和数字'): ValidateRule => ({
        pattern: REGEX.englishNumber,
        message,
        trigger: 'blur'
    }),

    /**
     * 密码验证
     */
    password: (message = '密码应为6-20位字母数字组合'): ValidateRule => ({
        pattern: REGEX.password,
        message,
        trigger: 'blur'
    }),

    /**
     * 强密码验证
     */
    strongPassword: (message = '密码应为8-20位，包含大小写字母、数字、特殊字符'): ValidateRule => ({
        pattern: REGEX.strongPassword,
        message,
        trigger: 'blur'
    }),

    /**
     * 确认密码验证
     */
    confirmPassword: (passwordField: string, message = '两次输入的密码不一致'): ValidateRule => ({
        validator: (rule: any, value: any, callback: Function) => {
            const form = rule.form
            if (value && value !== form[passwordField]) {
                callback(new Error(message))
            } else {
                callback()
            }
        },
        trigger: 'blur'
    }),

    /**
     * 自定义正则验证
     */
    pattern: (pattern: RegExp, message = '格式不正确'): ValidateRule => ({
        pattern,
        message,
        trigger: 'blur'
    }),

    /**
     * 自定义验证函数
     */
    custom: (validator: (rule: any, value: any, callback: Function) => void): ValidateRule => ({
        validator,
        trigger: 'blur'
    })
}

// 组合验证规则
export const combineRules = (...rules: ValidateRule[]): ValidateRule[] => {
    return rules
}

// 常用验证规则组合
export const commonRules = {
    // 用户名（4-16位英文数字）
    username: combineRules(
        validators.required('请输入用户名'),
        validators.length(4, 16, '用户名应为4-16位字符'),
        validators.englishNumber('用户名只能包含英文和数字')
    ),

    // 密码
    password: combineRules(
        validators.required('请输入密码'),
        validators.password()
    ),

    // 强密码
    strongPassword: combineRules(
        validators.required('请输入密码'),
        validators.strongPassword()
    ),

    // 手机号
    mobile: combineRules(
        validators.required('请输入手机号'),
        validators.mobile()
    ),

    // 邮箱
    email: combineRules(
        validators.required('请输入邮箱'),
        validators.email()
    ),

    // 姓名（2-10位中文）
    name: combineRules(
        validators.required('请输入姓名'),
        validators.length(2, 10, '姓名应为2-10位字符'),
        validators.chinese('姓名只能输入中文')
    ),

    // 身份证号
    idCard: combineRules(
        validators.required('请输入身份证号'),
        validators.idCard()
    ),

    // 银行卡号
    bankCard: combineRules(
        validators.required('请输入银行卡号'),
        validators.pattern(REGEX.bankCard, '请输入正确的银行卡号')
    ),

    // 车牌号
    carNumber: combineRules(
        validators.required('请输入车牌号'),
        validators.pattern(REGEX.carNumber, '请输入正确的车牌号')
    )
}

// 验证工具函数
export const validateUtils = {
    /**
     * 验证手机号
     */
    isMobile: (mobile: string): boolean => {
        return REGEX.mobile.test(mobile)
    },

    /**
     * 验证邮箱
     */
    isEmail: (email: string): boolean => {
        return REGEX.email.test(email)
    },

    /**
     * 验证身份证号
     */
    isIdCard: (idCard: string): boolean => {
        return REGEX.idCard.test(idCard)
    },

    /**
     * 验证网址
     */
    isUrl: (url: string): boolean => {
        return REGEX.url.test(url)
    },

    /**
     * 验证中文
     */
    isChinese: (str: string): boolean => {
        return REGEX.chinese.test(str)
    },

    /**
     * 验证英文
     */
    isEnglish: (str: string): boolean => {
        return REGEX.english.test(str)
    },

    /**
     * 验证数字
     */
    isNumber: (str: string): boolean => {
        return REGEX.number.test(str)
    },

    /**
     * 验证整数
     */
    isInteger: (str: string): boolean => {
        return REGEX.integer.test(str)
    },

    /**
     * 验证小数
     */
    isDecimal: (str: string): boolean => {
        return REGEX.decimal.test(str)
    },

    /**
     * 验证银行卡号
     */
    isBankCard: (bankCard: string): boolean => {
        return REGEX.bankCard.test(bankCard)
    },

    /**
     * 验证车牌号
     */
    isCarNumber: (carNumber: string): boolean => {
        return REGEX.carNumber.test(carNumber)
    },

    /**
     * 验证密码强度
     * @param password 密码
     * @returns 0-弱, 1-中, 2-强
     */
    getPasswordStrength: (password: string): number => {
        let strength = 0

        // 长度检查
        if (password.length >= 8) strength++

        // 包含数字
        if (/\d/.test(password)) strength++

        // 包含小写字母
        if (/[a-z]/.test(password)) strength++

        // 包含大写字母
        if (/[A-Z]/.test(password)) strength++

        // 包含特殊字符
        if (/[@$!%*?&]/.test(password)) strength++

        if (strength < 3) return 0 // 弱
        if (strength < 5) return 1 // 中
        return 2 // 强
    },

    /**
     * 身份证号码校验
     */
    validateIdCard: (idCard: string): { valid: boolean; message: string } => {
        if (!REGEX.idCard.test(idCard)) {
            return { valid: false, message: '身份证号格式不正确' }
        }

        if (idCard.length === 18) {
            // 18位身份证校验
            const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
            const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']

            let sum = 0
            for (let i = 0; i < 17; i++) {
                sum += parseInt(idCard[i]) * weights[i]
            }

            const checkCode = checkCodes[sum % 11]
            const lastChar = idCard[17].toUpperCase()

            if (checkCode !== lastChar) {
                return { valid: false, message: '身份证号校验码不正确' }
            }
        }

        return { valid: true, message: '身份证号验证通过' }
    }
}

export default {
    REGEX,
    validators,
    combineRules,
    commonRules,
    validateUtils
}
